package com.market.manager.impl;

import java.util.List;

import javax.faces.application.ConfigurableNavigationHandler;
import javax.faces.context.FacesContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.market.dao.UserActivityRecordDao;
import com.market.dao.UserDao;
import com.market.domain.BaseObject;
import com.market.domain.Message;
import com.market.domain.Order;
import com.market.domain.Role;
import com.market.domain.User;
import com.market.domain.UserActivityRecord;
import com.market.domain.UserActivityRecord.TYPE;
import com.market.domain.transients.UserAuthentication;
import com.market.manager.UserManager;
import com.market.web.model.UserModel;

@Service("userManager")
public class UserManagerImpl extends GenericManagerImpl<UserDao, User, Long>
		implements UserManager, UserDetailsService {

	@Autowired
	UserActivityRecordDao userActivityRecordDao;

	@Autowired
	public void setDao(UserDao userDao) {
		this.dao = userDao;
	}

	public List<Role> fetchRoles(User user) {
		return this.dao.findRoles(user);
	}

	public List<Message> fetchMessages(User user) {
		return this.dao.findMessages(user);
	}

	public List<Order> fetchOrders(User user) {
		return this.dao.findOrders(user);
	}

	public User fetchOne(Long id) {
		User user = this.dao.findById(id);
		user.setRoles(this.dao.findRoles(user));
		user.setMessages(this.dao.findMessages(user));
		user.setOrders(this.dao.findOrders(user));
		user.setAccountRecords(this.dao.findAccountRecords(user));
		user.setUserActivityRecords(this.dao.findUserActivityRecords(user));
		return user;
	}

	public User fetchOne(User user) {
		if (user != null && user.getIsNew() == false) {
			return this.fetchOne(user.getId());
		}
		return user;
	}

	public User fetchByEmailAndPassword(String email, String password) {
		User user = this.dao.findByEmailAndPassword(email, password);
		if (user != null) {
			user.setRoles(this.dao.findRoles(user));
			user.setMessages(this.dao.findMessages(user));
			user.setOrders(this.dao.findOrders(user));
			user.setUserActivityRecords(this.dao.findUserActivityRecords(user));
		}
		return user;
	}

	public User fetchByEmail(String email) {
		User user = this.dao.findByEmail(email);
		if (user != null) {
			user.setRoles(this.dao.findRoles(user));
			user.setMessages(this.dao.findMessages(user));
			user.setOrders(this.dao.findOrders(user));
			user.setUserActivityRecords(this.dao.findUserActivityRecords(user));
		}
		return user;
	}

	public User loginByEmail(User user) {
		Boolean isAccountValid = Boolean.TRUE;
		User userFromDB = this.fetchByEmail(user.getEmail());

		if (userFromDB != null) {
			UserActivityRecord record = new UserActivityRecord();
			if (userFromDB.getIsActivated() == Boolean.FALSE) {
				record.setComments("Not activated");
				isAccountValid = Boolean.FALSE;
			}

			if (userFromDB.getIsEnabled() == Boolean.FALSE) {
				record.setComments("Account is not enable");
				isAccountValid = Boolean.FALSE;
			}
			if (userFromDB.getIsLocked() == Boolean.TRUE) {
				record.setComments("Account is locked");
				isAccountValid = Boolean.FALSE;
			}
			if (userFromDB.getIsExpired() == Boolean.TRUE) {
				record.setComments("Account is expired");
				isAccountValid = Boolean.FALSE;
			}
			if (isAccountValid == Boolean.TRUE) {
				if (userFromDB.getPassword().equals(user.getPassword())) {
					record.setType(TYPE.LOG_IN_SUCCEED);
					userFromDB.setIsLogin(Boolean.TRUE);
				} else {
					record.setType(TYPE.LOG_IN_FAILED);
					record.setComments("Password is '"
							+ userFromDB.getPassword() + "', not '"
							+ user.getPassword() + "'");
				}
			} else {
				record.setType(TYPE.LOG_IN_FAILED);
			}
			// record = this.userActivityRecordDao.save(record); //
			// Ｔｈｉｓ　ｌｉｎｅ　ｓｕｐｐｏｓｅ　ｔｏ　ｂｅ　ｎｅｅｄｅｄ.　Ｗｈｙ　ｎｏｔ?　Ｉ　ｄｏｎ'ｔ　ｋｎｏｗ.
			userFromDB.getUserActivityRecords().add(record);
			userFromDB = this.dao.save(userFromDB);
		}

		return userFromDB;
	}

	public User fetchByTelephone(String telephone) {
		User user = this.dao.findByTelephone(telephone);
		if (user != null) {
			user.setRoles(this.dao.findRoles(user));
			user.setMessages(this.dao.findMessages(user));
			user.setOrders(this.dao.findOrders(user));
			user.setUserActivityRecords(this.dao.findUserActivityRecords(user));
		}
		return user;
	}

	public User loginByTelephone(User user) {
		Boolean isAccountValid = Boolean.TRUE;
		User userFromDB = this.fetchByTelephone(user.getTelephone());
		if (userFromDB != null) {
			UserActivityRecord record = new UserActivityRecord();
			if (userFromDB.getIsActivated() == Boolean.FALSE) {
				isAccountValid = Boolean.FALSE;
				record.setComments("Not activated");
			}

			if (userFromDB.getIsEnabled() == Boolean.FALSE) {
				isAccountValid = Boolean.FALSE;
				record.setComments("Account is not enable");
			}
			if (userFromDB.getIsLocked() == Boolean.TRUE) {
				isAccountValid = Boolean.FALSE;
				record.setComments("Account is locked");
			}
			if (userFromDB.getIsExpired() == Boolean.TRUE) {
				isAccountValid = Boolean.FALSE;
				record.setComments("Account is expired");
			}
			if (isAccountValid == Boolean.TRUE) {
				if (userFromDB.getPassword().equals(user.getConfirmPassword())) {
					record.setType(UserActivityRecord.TYPE.LOG_IN_SUCCEED);
					userFromDB.setIsLogin(Boolean.TRUE);
				} else {
					record.setType(TYPE.LOG_IN_FAILED);
					record.setComments("Password is '"
							+ userFromDB.getPassword() + "', not '"
							+ user.getPassword() + "'");
				}
			}else {
				record.setType(TYPE.LOG_IN_FAILED);
			}

			// record = this.userActivityRecordDao.save(record); //
			// Ｔｈｉｓ　ｌｉｎｅ　ｓｕｐｐｏｓｅ　ｔｏ　ｂｅ　ｎｅｅｄｅｄ.　Ｗｈｙ　ｎｏｔ?　Ｉ　ｄｏｎ'ｔ　ｋｎｏｗ.
			userFromDB.getUserActivityRecords().add(record);
			userFromDB = this.dao.save(userFromDB);
		}
		return userFromDB;
	}

	@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		User userFromDB = this.fetchByEmail(username);
		if (userFromDB != null) {
			UserActivityRecord record = new UserActivityRecord();
			if (userFromDB.getIsActivated() == Boolean.FALSE) {
				record.setType(TYPE.LOG_IN_FAILED);
				record.setComments("Not activated");
			}

			if (userFromDB.getIsEnabled() == Boolean.FALSE) {
				record.setType(TYPE.LOG_IN_FAILED);
				record.setComments("Account is not enable");
			}
			if (userFromDB.getIsLocked() == Boolean.TRUE) {
				record.setType(TYPE.LOG_IN_FAILED);
				record.setComments("Account is locked");
			}
			if (userFromDB.getIsExpired() == Boolean.TRUE) {
				record.setType(TYPE.LOG_IN_FAILED);
				record.setComments("Account is expired");
			}
			// record = this.userActivityRecordDao.save(record); //
			// Ｔｈｉｓ　ｌｉｎｅ　ｓｕｐｐｏｓｅ　ｔｏ　ｂｅ　ｎｅｅｄｅｄ.　Ｗｈｙ　ｎｏｔ?　Ｉ　ｄｏｎ'ｔ　ｋｎｏｗ.
			userFromDB.getUserActivityRecords().add(record);
			userFromDB = this.dao.save(userFromDB);
		}
		return userFromDB;
	}

	public User activateAccount(Long id, String activatedCode) {
		User user = this.dao.activateAccount(id, activatedCode);
		if (user != null) {
			User userFromDB = this.fetchOne(user.getId());
			UserActivityRecord record = new UserActivityRecord();
			record.setType(UserActivityRecord.TYPE.ACTIVATION_LOG_IN);
			if (userFromDB.getIsActivated() == Boolean.FALSE) {
				record.setComments("Not activated");
			}

			if (userFromDB.getIsEnabled() == Boolean.FALSE) {
				record.setComments("Account is not enable");
			}
			if (userFromDB.getIsLocked() == Boolean.TRUE) {
				record.setComments("Account is locked");
			}
			if (userFromDB.getIsExpired() == Boolean.TRUE) {
				record.setComments("Account is expired");
			}
			// record = this.userActivityRecordDao.save(record); //
			// Ｔｈｉｓ　ｌｉｎｅ　ｓｕｐｐｏｓｅ　ｔｏ　ｂｅ　ｎｅｅｄｅｄ.　Ｗｈｙ　ｎｏｔ?　Ｉ　ｄｏｎ'ｔ　ｋｎｏｗ.
			userFromDB.getUserActivityRecords().add(record);
			userFromDB = this.dao.save(userFromDB);
			return userFromDB;
		}
		return null;
	}

}
